#!/usr/bin/env ruby
# frozen_string_literal: true

# mishmat: Generate a matrix visualization of mishegos results in HTML

require "erb"
require "optparse"
require "json"

COLOR_TABLE = Hash.new("#808080").update(
  "success" => "#00FF00",
  "failure" => "#FF0000",
  "none" => "#0000FF",
  "partial" => "#808080",
  "unknown" => "#4B0082"
)

HEADER = ERB.new <<~HTML
  <!DOCTYPE html>
  <html>
    <head>
      <meta charset="utf-8">
      <meta generator="mishmash (mishegos)">
      <meta timestamp="#{Time.now.to_i}">
      <style type="text/css">
        table, th, td {
          border: 1px solid black;
        }

        th, td {
          text-align: left;
        }
      </style>
    </head>

  <body>
    <h1>mishmat (mishegos)</h1>

    <h2>legend</h2>
    <table>
      <% COLOR_TABLE.each do |color, hex| %>
        <tr>
          <td><%= color %></td>
          <td style="background-color: <%= hex %>; width: 10px"></td>
        </tr>
      <% end %>
    </table>

    <br><br><br>

    <table>
HTML

HEADER_ROWS = ERB.new <<~HTML
  <tr>
    <th>input</th>
    <th colspan="100">worker</th>
  </tr>

  <tr>
    <th></th>
    <% row[:outputs].each do |col| %>
      <th>
        <%= col[:worker_so] %>
      </th>
    <% end %>
  </tr>
HTML

ENTRY_ROW = ERB.new <<~HTML
  <tr>
    <td>
      <code><%= row[:input] %></code>
    </td>
    <% row[:outputs].each do |col| %>
      <td style="background-color: <%= COLOR_TABLE[col[:status][:name]] %>">
        <code><%= col[:result] %></code> (<%= col[:ndecoded] %> / <%= col[:len] %>)
      </td>
    <% end %>
  </tr>
HTML

FOOTER = <<~HTML
  </table>
  </body>
  </html>
HTML

opts = {
  limit: Float::INFINITY,
}

def write_header!(row)
  STDOUT.puts HEADER.result(binding)
  STDOUT.puts HEADER_ROWS.result(binding)
end

def write_footer!
  STDOUT.puts FOOTER
end

def write_row!(row)
  STDOUT.puts ENTRY_ROW.result(binding)
end

OptionParser.new do |o|
  o.banner = "Usage: mishmat [options]"

  o.on "-l", "--limit LIMIT", Integer, "Entry cap" do |limit|
    opts[:limit] = limit
  end
end.parse!

# Special-case the first row: We need to grab the figure out the appropriate number of
# columns and their headers.
row = JSON.parse STDIN.gets, symbolize_names: true
write_header! row
write_row! row

STDIN.each_line.with_index do |line, i|
  break if i >= opts[:limit]

  write_row! JSON.parse(line, symbolize_names: true)
end

write_footer!
